package bot.module.th.estimation;

import game.gamestorage.texas.db.estimation.GetterDBProjector;
import game.model.Card;
import util.DebugOut;
import util.sql.DBHelper;
import bot.module.th.shc.StartingHandChart;

/**
 * This class estimates the opponents first action of a hand by comparing to a startinghandchart
 * 
 * @author Witthold/Korol
 */
public class PreFlopShc implements IF_EstimationAtRound {

	private int initLoose = 50;
	private int initAggression = 50;	
	/**
	 * shc comparison - consider: tightness only via folds/totalBets<br>
	 * int[0]: relation looseness, 0-100<br>
	 * int[1]: relation aggression, 0-100<br>
	 * int[2]: numMoreLoose<br>
	 * int[3]: numMorePassive<br>
	 * int[4]: numMoreAggressive<br>
	 * int[5]: evaledBets<br>
	 * int[6]: totalBets
	 */
	protected int[] behaviour = new int[7];	
	/** 
	 * amount of
	 * int[0]: folds<br>
	 * int[1]: checks, calls<br>
	 * int[2]: raises<br>
	 * int[3]: allIns<br>
	 */
	private int[] actions = new int[4];
	private GetterDBProjector gDBP;
	private StartingHandChart shc;


	/**
	 * Constructor inits some fields
	 * 
	 * @param shc - the StartingHandChart to compare with
	 */
	public PreFlopShc(StartingHandChart shc) {

		this.shc = shc;

		/* init fields */
		behaviour[0] = initLoose;
		behaviour[1] = initAggression;
		
//		int avgNumActivePlayers = 0;
//
//		for (Integer key : gDBP.getNumActivePlayersCO().keySet()) {
//			avgNumActivePlayers += gDBP.getNumActivePlayersCO().get(key);
//		}
//		avgNumActivePlayers = avgNumActivePlayers / gDBP.getNumActivePlayersCO().size();
//				DebugOut.showVerboseEstimation("avgNumActivePlayers: " + avgNumActivePlayers);
//		initLoose = 30 + avgNumActivePlayers * 3; // TODO tuning		
	}


	/* (non-Javadoc)
	 * @see bot.module.th.estimation.IF_EstimationAtRound#fetchData(game.gamestorage.texas.db.estimation.GetterDBProjector, int, int, int)
	 */
	@Override
	public void fetchData(GetterDBProjector gDBP) {
		this.gDBP = gDBP;
		gDBP.setPreFlopShcData();

		/* evaledBets */
		behaviour[5] = gDBP.getHandPlayerMapCO().size();
		/* totalBets */
		behaviour[6] = gDBP.getRoundsFirstBetsAll().size();	/* consider case: win by rest folded in last position */
		
		relationizeShcBets();
	}
	


	/* (non-Javadoc)
	 * @see bot.module.th.estimation.IF_EstimationAtRound#estimate()
	 */
	@Override
	public void estimate() {

		askShc();
	}


	/**
	 * what would the given startingHandChart had proposed
	 */
	private void askShc() {

		for (Integer key : gDBP.getHandPlayerMapCO().keySet()) {

			/* holeCards */		
			Card[] holeCards = DBHelper.cardsDBToCardArr(gDBP.getHoleCards().get(key));

			/* activePlayers */
			int numAP = gDBP.getNumActivePlayersCO().get(key);

			/* Blinds */
			int sb = gDBP.getHandsCO().get(gDBP.getHandPlayerMapCO().get(key)[3])[0];
			int bb = gDBP.getHandsCO().get(gDBP.getHandPlayerMapCO().get(key)[3])[1];

			/* Position */
			int position = (gDBP.getHandPlayerMapCO().get(key)[0]);

			/* Calls, Raises */
			int numCalls = 0;
			int numRaises = 0;

			if (gDBP.getHpmsPreviousActionsCO().containsKey(key)) {
				for (int i = 0; i < gDBP.getHpmsPreviousActionsCO().get(key).length; i++) {
					if (gDBP.getHpmsPreviousActionsCO().get(key)[i] > -1) { // Check: 0, Call: 1
						if (gDBP.getHpmsPreviousActionsCO().get(key)[i] > 4) { // Raise: 5, Allin: 9
							numRaises++;
						} else {
							numCalls++;
						}
					}
				}
			}

			// ask shc
			int proposal = shc.getProposal(holeCards, numAP, sb, bb, position, numCalls, numRaises)[0];
			int hisAction = (int) gDBP.getHpmsFirstBetsCO().get(key)[0];
			int betsize = (int) gDBP.getHpmsFirstBetsCO().get(key)[1];

			compareToShc(proposal, hisAction, betsize, bb);
		}
	}


	/**
	 * compare players action to startingHandCharts proposal 
	 * 
	 * @param proposal
	 * @param hisAction
	 * @param betsize
	 * @param bb - bigblind
	 */
	private void compareToShc(int proposal, int hisAction, int betsize, int bb) {
		//		DebugOut.showVerboseEstimation("shc " + proposal + "   -   " + hisAction);		

		if (proposal == -1) { // shc would have folded
			behaviour[2]++;
			return;
		}
		if (proposal <= 1 && hisAction > 1) { // shc:c; player:r
			behaviour[4]++;
			return;
		}
		if (proposal > 1 && hisAction <= 1) { // r vs c (3||4 vs 0||1)
			behaviour[3]++;
			return;
		}
		if (proposal * bb > betsize) {
			behaviour[3]++;
			return;
		}
		if (proposal * bb < betsize) {
			behaviour[4]++;
			return;
		}
		System.err.println("PreFlopShc: behaviour: Should not reach here!");
	}

	/**
	 * relation of all bets - count actions
	 */
	private void relationizeShcBets() {
		
		
		
		for (Integer key : gDBP.getRoundsFirstBetsAll().keySet()) {
			
			long action = gDBP.getRoundsFirstBetsAll().get(key)[1];
			
			if(action == -1) {
				actions[0]++;
			}else if(action < 2) {
				actions[1]++;
			}else if(action == 5) {
				actions[2]++;
			}else if(action == 9) {
				actions[3]++;
			}else {
				System.err.println("PreFlopShc: relationizeShcBets: wrong value, got: " + action);	
			}
		}
		
	}

	/* (non-Javadoc)
	 * @see bot.module.th.estimation.IF_EstimationAtRound#mergeIntoRound()
	 */
	@Override
	public void mergeIntoRound() {

		/* calculate looseness 
		 * regard having no actions at all
		 */			
		if(behaviour[6]>0) {
			behaviour[0] = initLoose + (100 - initLoose) * behaviour[2] / behaviour[6];
		} else {
			DebugOut.showVerboseEstimation("no actions at all");
		}
		
		/* calculate aggression
		 * regard having no evaled actions
		 */
		if(behaviour[5]>0) {
		behaviour[1] = initAggression + (100 - initAggression) * (behaviour[4] - behaviour[3]) / behaviour[5];
		} else {
			DebugOut.showVerboseEstimation("no evaled actions");
		}
		
		/* DebugOut */
//		DebugOut.showVerboseEstimation("behaviour looseness: " + behaviour[0]);
//		DebugOut.showVerboseEstimation("behaviour aggression: " + behaviour[1]);
		for (int i = 0; i < behaviour.length; i++) {
			DebugOut.showVerboseEstimation("shcComparison_" + i + ": " + behaviour[i]);
		}
		DebugOut.showVerboseEstimation("evaled: " + behaviour[5] + ", total: " + behaviour[6]);
	}


	/* (non-Javadoc)
	 * @see bot.module.th.estimation.IF_EstimationAtRound#mergeIntoOverall()
	 */
	@Override
	public void mergeIntoOverall(Opponent o) {

		for (int i = 0; i < actions.length; i++) {
			DebugOut.showVerboseEstimation("actions" + i + ": " + actions[i]);
		}
		
		int[] cat = {behaviour[0], behaviour[1], 0};
		o.setBehaviourAtRound(0, cat);
		
		o.setActionAtRound(0, actions);
		
	}

}